/********************************************************************************
* @file    app_io.h
* @author  jianqiang.xue
* @version V1.0.2
* @date    2023-07-04
* @brief   IO功能
* @note    1. 支持IO、ADC、PWM
********************************************************************************/

#ifndef __APP_IO_H
#define __APP_IO_H

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>

#include "ls_syscfg.h"
#include "ls_gpio.h"

#include "bsp_gpio.h"
#include "bsp_exti.h"
#include "bsp_uart.h"
#include "bsp_tim.h"
#include "bsp_pwm.h"
#include "bsp_adc.h"
/* Public Define -------------------------------------------------------------*/
#define IO_VERSION      "1.4"
typedef void(*io_irq_callback)(void);

/* Public Enum ---------------------------------------------------------------*/
typedef enum {
    IO_EVENT_NULL    = 0,
    IO_EVENT_IO_LOW, // 中断事件
    IO_EVENT_IO_HIGH,
    IO_EVENT_IO_KEY_SINGLE_CLICK,      // 按键事件
    IO_EVENT_IO_KEY_TWO_CLICK,         // 双击
    IO_EVENT_IO_KEY_LONG_PRESS,        // 长按3秒
    IO_EVENT_IO_KEY_LONG_LONG_PRESS,   // 长按10秒
} io_event_t;

/* Typedef Struct ------------------------------------------------------------*/
typedef struct __PACKED {
    union io_support_t support;
    uint8_t key_num;
    uint8_t matrix_x_num : 4;
    uint8_t matrix_y_num : 4;
} io_cfg_record_t; // 用于记录初始化过程中支持的功能和按键数量

typedef struct __PACKED { // 功能支持标记位
    uint16_t save_support          : 1; // 0 -- 不支持保存配置     1 -- 支持保存配置
    uint16_t active_report_support : 1; // 0 -- 不支持主动上报     1 -- 支持主动上报
    uint16_t key_support           : 1; // 0 -- 不支持按键扫描     1 -- 支持按键扫描
    uint16_t matrix_key_support    : 1; // 0 -- 不支持矩阵键盘     1 -- 支持矩阵键盘
    uint16_t timer_support         : 1; // 0 -- 不支持IO定时器     1 -- 支持IO定时器
    uint16_t sys_vcc_support       : 1; // 0 -- 不支持ADC电池通道  1 -- 支持ADC电池通道(需要在ls_syscfg.h--ADC0--sys_vcc使能)
    uint16_t swo_off               : 1; // 0 -- 开启    1 -- 禁用
                                        /* 如果禁用，将无法烧录和仿真。并且引脚将设置为输出状态。
                                        不可以设置输入，如果外部拉住，将无法恢复使用。*/
    uint16_t nonuse_default_cfg    : 1; // 是否使用默认配置 0--使用 1--不使用  如果flash没有配置，则使用默认配置

    uint16_t reserve               : 7; // 预留
    uint16_t write_in              : 1; // flash是否写入 0--false 1--true
} io_flag_t;

typedef struct __PACKED { // io类型 状态 事件
    uint8_t level         : 1; // 0--低电平 1--高电平
    io_event_t io_event   : 3;
    uint8_t reserve       : 4; // 预留
} io_func_t;

typedef struct __PACKED {
    uint16_t time;          // 间隔时间ms
    uint8_t event      : 4; // // 0--低电平 1--高电平 2--翻转电平 3--指定亮度(0-100%) 4--翻转电平指定亮度(0-100%) 5--缓慢上升 6--缓慢下降 -1--无效
    uint8_t reserve    : 4;
    uint8_t target_num : 4; // 目标次数 0-15
    uint8_t cnt        : 4; // 记录次数 0-15
    uint8_t target_val;     // 目标值(0-100%)
    uint8_t init_val;       // 初始值(0-100%)
    uint8_t val;            // 记录值(0-100%)
} io_task_parm_t;

typedef struct __PACKED {
    uint8_t step             : 3; // 0--NULL, 1--start_time_end, 2--start_parm_end, 3--stop_parm_end, 4--wait_stop_time_end, 5--stop_time_end
    uint8_t is_valid         : 1; // 是否有效
    uint8_t is_repeat        : 4; // 是否重复  0--无限重复  >1根据次数重复
    uint8_t start_event      : 2; // 0--低电平 1--高电平 2--翻转电平 -1--无效
    uint8_t stop_event       : 2; // 0--低电平 1--高电平 2--翻转电平 -1--无效
    uint8_t task_id          : 4; // 记录当前任务ID，便于下次查找指定ID. 0-15
    uint8_t io;                // 执行操作的IO引脚号
    uint16_t countdown;        // 毫秒级 计数器
    uint16_t start_time;       // 目标启动时间 毫秒级 【多少毫秒后，启动】
    io_task_parm_t start_parm; // 任务参数
    io_task_parm_t stop_parm;  // 任务参数
    uint16_t stop_time;        // 目标停止时间 毫秒级 【停止多少毫秒后结束本轮】
    void* next_task;           // 下一个任务地址
} io_task_t;


typedef void (*app_io_out)(uint8_t io, io_ste_t ste);
typedef bool (*app_io_in)(uint8_t io);

typedef struct __attribute__((packed, aligned(1))) { // 芯片当前io配置
#if LS_APP_IO_CHANGE_SUPPORT
    io_type_t type[LS_IO_NUM]; // 此处类型是实际使用，g_io_cgh是默认使用
#endif
    io_func_t func[LS_IO_NUM]; // 当前io电平状态/按键事件/中断事件
    io_flag_t flag;            // 功能支持标记位

    app_io_out out;// 设置电平(io, 电平)
    app_io_in in; // 电平状态(io)
} ls_io_t;
/* External Variables --------------------------------------------------------*/
extern ls_io_t g_io;
// extern io_cfg_record_t g_cfg_record;

#if LS_APP_IO_TIMER_SUPPORT
extern io_task_t *g_io_task;
extern uint8_t g_io_task_num;
extern uint32_t g_timer_io_time_ms; // 软件定时器的基准时间
#endif
/* Public Macro --------------------------------------------------------------*/
/* Public Function Prototypes ------------------------------------------------*/
void app_io_init(void);
void app_io_deinit(void);
bool flash_read_app_io_all(void);
bool flash_write_app_io_all(void);

void io_init_all(io_type_t * type, bool is_save);
bool io_cfg(uint8_t id, io_type_t *io_type, io_cfg_record_t *cfg_record);
void io_cfg_task_and_peripheral(io_cfg_record_t *cfg_record);

// 当出现外部中断、按键事件等等，则使用signal_irq()，点亮LED。
void signal_irq(void);
// 当读取事件完毕后，使用clean_signal_irq()，清除所有事件标记。并熄灭LED。
void clean_signal_irq(void);

void app_io_exti_cb(void *gpiox, uint16_t gpio_pin);

// 弱函数 ，当有按键事件时，就回调。默认功能，触发LED指示灯。如果外部重定义，触发LED指示灯将失效。
void key_event(uint8_t event);

uint8_t app_adc0_timer_start(void);
void app_adc0_timer_stop(void);
#endif
